# encoding: utf-8
# @File  : grafana_integration.py
# @Author: shaoyun
# @Date  :  2025/05/11

from typing import Dict, List, Any

import httpx
from loguru import logger

from app.core.config import settings


class GrafanaIntegration:
    """Grafana集成模块"""

    def __init__(self):
        self.base_url = f"http://{settings.GRAFANA_HOST}:{settings.GRAFANA_PORT}"
        self.api_key = settings.GRAFANA_API_KEY

    async def create_dashboard(self) -> Dict[str, Any]:
        """创建分布式爬虫监控仪表板"""
        dashboard_config = {
            "dashboard": {
                "title": "分布式爬虫管理系统监控",
                "panels": [
                    # 第一行：概览指标
                    self._create_health_score_panel(),
                    self._create_task_status_panel(),
                    self._create_node_status_panel(),

                    # 第二行：性能指标
                    self._create_task_duration_panel(),
                    self._create_node_load_panel(),
                    self._create_queue_size_panel(),

                    # 第三行：告警和趋势
                    self._create_alert_panel(),
                    self._create_task_trend_panel(),
                    self._create_failure_rate_panel()
                ],
                "refresh": "10s",
                "time": {
                    "from": "now-1h",
                    "to": "now"
                },
                "timezone": "browser",
                "schemaVersion": 30
            },
            "overwrite": True
        }

        try:
            async with httpx.AsyncClient() as client:
                response = await client.post(
                    f"{self.base_url}/api/dashboards/db",
                    headers={
                        "Authorization": f"Bearer {self.api_key}",
                        "Content-Type": "application/json"
                    },
                    json=dashboard_config,
                    timeout=30.0
                )

                if response.status_code == 200:
                    logger.info("Grafana dashboard created successfully")
                    return response.json()
                else:
                    logger.error(f"Failed to create dashboard: {response.text}")
                    return {"error": response.text}
        except Exception as e:
            logger.error(f"Error creating Grafana dashboard: {e}")
            return {"error": str(e)}

    def _create_health_score_panel(self) -> Dict[str, Any]:
        """创建系统健康分数面板"""
        return {
            "title": "系统健康分数",
            "type": "stat",
            "gridPos": {"x": 0, "y": 0, "w": 8, "h": 4},
            "targets": [{
                "expr": '100 - (sum(increase(crawler_tasks_total{status="failed"}[5m])) / sum(increase(crawler_tasks_total[5m])) * 100)',
                "legendFormat": "健康分数",
                "refId": "A"
            }],
            "fieldConfig": {
                "defaults": {
                    "unit": "percent",
                    "thresholds": {
                        "mode": "absolute",
                        "steps": [
                            {"color": "red", "value": 0},
                            {"color": "yellow", "value": 70},
                            {"color": "green", "value": 90}
                        ]
                    }
                }
            }
        }

    def _create_task_status_panel(self) -> Dict[str, Any]:
        """创建任务状态面板"""
        return {
            "title": "任务执行状态",
            "type": "piechart",
            "gridPos": {"x": 8, "y": 0, "w": 8, "h": 4},
            "targets": [{
                "expr": 'crawler_tasks_current',
                "legendFormat": "{{status}}",
                "refId": "A"
            }],
            "options": {
                "pieType": "donut",
                "displayLabels": ["name", "percent"],
                "legendDisplayMode": "table",
                "legendPlacement": "right"
            }
        }

    def _create_node_status_panel(self) -> Dict[str, Any]:
        """创建节点状态面板"""
        return {
            "title": "节点状态",
            "type": "stat",
            "gridPos": {"x": 16, "y": 0, "w": 8, "h": 4},
            "targets": [
                {
                    "expr": 'crawler_nodes{status="online"}',
                    "legendFormat": "在线节点",
                    "refId": "A"
                },
                {
                    "expr": 'crawler_nodes{status="offline"}',
                    "legendFormat": "离线节点",
                    "refId": "B"
                }
            ],
            "options": {
                "graphMode": "none",
                "colorMode": "value"
            }
        }

    def _create_task_duration_panel(self) -> Dict[str, Any]:
        """创建任务执行时间面板"""
        return {
            "title": "任务执行时间分布",
            "type": "histogram",
            "gridPos": {"x": 0, "y": 4, "w": 12, "h": 8},
            "targets": [{
                "expr": 'histogram_quantile(0.95, sum(rate(crawler_task_duration_seconds_bucket[5m])) by (le))',
                "legendFormat": "P95执行时间",
                "refId": "A"
            }],
            "fieldConfig": {
                "defaults": {
                    "unit": "s",
                    "custom": {
                        "hideFrom": {
                            "tooltip": False,
                            "viz": False,
                            "legend": False
                        }
                    }
                }
            }
        }

    def _create_node_load_panel(self) -> Dict[str, Any]:
        """创建节点负载面板"""
        return {
            "title": "节点资源使用情况",
            "type": "timeseries",
            "gridPos": {"x": 12, "y": 4, "w": 12, "h": 8},
            "targets": [
                {
                    "expr": 'crawler_node_cpu_usage',
                    "legendFormat": "{{node_name}} - CPU",
                    "refId": "A"
                },
                {
                    "expr": 'crawler_node_memory_usage',
                    "legendFormat": "{{node_name}} - Memory",
                    "refId": "B"
                }
            ],
            "fieldConfig": {
                "defaults": {
                    "unit": "percent",
                    "max": 100,
                    "min": 0,
                    "custom": {
                        "lineWidth": 2,
                        "fillOpacity": 10
                    }
                }
            }
        }

    def _create_queue_size_panel(self) -> Dict[str, Any]:
        """创建任务队列大小面板"""
        return {
            "title": "任务队列",
            "type": "graph",
            "gridPos": {"x": 0, "y": 12, "w": 8, "h": 6},
            "targets": [
                {
                    "expr": 'crawler_task_queue_size',
                    "legendFormat": "队列长度",
                    "refId": "A"
                },
                {
                    "expr": 'crawler_active_tasks',
                    "legendFormat": "执行中任务",
                    "refId": "B"
                }
            ],
            "yaxis": {
                "align": False,
                "alignLevel": None
            }
        }

    def _create_alert_panel(self) -> Dict[str, Any]:
        """创建告警面板"""
        return {
            "title": "系统告警",
            "type": "table",
            "gridPos": {"x": 8, "y": 12, "w": 8, "h": 6},
            "targets": [{
                "expr": 'ALERTS{alertstate="firing", job="crawler_manager"}',
                "format": "table",
                "instant": True,
                "refId": "A"
            }],
            "options": {
                "showHeader": True
            },
            "fieldConfig": {
                "defaults": {
                    "custom": {
                        "align": "auto",
                        "displayMode": "auto"
                    }
                }
            }
        }

    def _create_task_trend_panel(self) -> Dict[str, Any]:
        """创建任务趋势面板"""
        return {
            "title": "任务执行趋势",
            "type": "graph",
            "gridPos": {"x": 16, "y": 12, "w": 8, "h": 6},
            "targets": [
                {
                    "expr": 'rate(crawler_tasks_total[5m])',
                    "legendFormat": "{{status}}",
                    "refId": "A"
                }
            ],
            "yaxis": {
                "label": "任务/秒",
                "align": False
            }
        }

    def _create_failure_rate_panel(self) -> Dict[str, Any]:
        """创建失败率面板"""
        return {
            "title": "任务失败率",
            "type": "gauge",
            "gridPos": {"x": 0, "y": 18, "w": 8, "h": 4},
            "targets": [{
                "expr": 'sum(rate(crawler_tasks_total{status="failed"}[5m])) / sum(rate(crawler_tasks_total[5m])) * 100',
                "legendFormat": "失败率",
                "refId": "A"
            }],
            "options": {
                "showThresholdLabels": False,
                "showThresholdMarkers": True
            },
            "fieldConfig": {
                "defaults": {
                    "unit": "percent",
                    "max": 100,
                    "min": 0,
                    "thresholds": {
                        "mode": "absolute",
                        "steps": [
                            {"color": "green", "value": 0},
                            {"color": "yellow", "value": 5},
                            {"color": "red", "value": 10}
                        ]
                    }
                }
            }
        }

    async def create_alerts(self) -> List[Dict[str, Any]]:
        """创建Grafana告警规则"""
        alerts = [
            {
                "uid": "node_offline_alert",
                "title": "节点离线告警",
                "condition": "avg",
                "data": [{
                    "refId": "A",
                    "queryType": "",
                    "model": {
                        "expr": 'crawler_nodes{status="offline"} > 0',
                        "intervalMs": 1000,
                        "maxDataPoints": 43200,
                        "refId": "A"
                    }
                }],
                "noDataState": "NoData",
                "execErrState": "Alerting",
                "for": "5m",
                "annotations": {
                    "description": "检测到离线节点",
                    "runbook_url": "",
                    "summary": "节点离线告警"
                },
                "labels": {
                    "severity": "warning"
                }
            },
            {
                "uid": "high_failure_rate_alert",
                "title": "高失败率告警",
                "condition": "avg",
                "data": [{
                    "refId": "A",
                    "queryType": "",
                    "model": {
                        "expr": 'sum(rate(crawler_tasks_total{status="failed"}[5m])) / sum(rate(crawler_tasks_total[5m])) > 0.1',
                        "intervalMs": 1000,
                        "maxDataPoints": 43200,
                        "refId": "A"
                    }
                }],
                "noDataState": "NoData",
                "execErrState": "Alerting",
                "for": "5m",
                "annotations": {
                    "description": "任务失败率超过10%",
                    "summary": "高失败率告警"
                },
                "labels": {
                    "severity": "critical"
                }
            },
            {
                "uid": "queue_backlog_alert",
                "title": "队列堆积告警",
                "condition": "avg",
                "data": [{
                    "refId": "A",
                    "queryType": "",
                    "model": {
                        "expr": 'crawler_task_queue_size > 100',
                        "intervalMs": 1000,
                        "maxDataPoints": 43200,
                        "refId": "A"
                    }
                }],
                "noDataState": "NoData",
                "execErrState": "Alerting",
                "for": "10m",
                "annotations": {
                    "description": "任务队列堆积超过100个任务",
                    "summary": "队列堆积告警"
                },
                "labels": {
                    "severity": "warning"
                }
            }
        ]

        created_alerts = []
        for alert in alerts:
            try:
                async with httpx.AsyncClient() as client:
                    response = await client.post(
                        f"{self.base_url}/api/v1/provisioning/alert-rules",
                        headers={
                            "Authorization": f"Bearer {self.api_key}",
                            "Content-Type": "application/json"
                        },
                        json=alert,
                        timeout=30.0
                    )

                    if response.status_code in [200, 201]:
                        created_alerts.append(alert)
                        logger.info(f"Alert rule '{alert['title']}' created successfully")
                    else:
                        logger.error(f"Failed to create alert rule '{alert['title']}': {response.text}")
            except Exception as e:
                logger.error(f"Error creating alert rule '{alert['title']}': {e}")

        return created_alerts

    async def test_connection(self) -> bool:
        """测试Grafana连接"""
        try:
            async with httpx.AsyncClient() as client:
                response = await client.get(
                    f"{self.base_url}/api/health",
                    headers={
                        "Authorization": f"Bearer {self.api_key}"
                    },
                    timeout=10.0
                )

                if response.status_code == 200:
                    logger.info("Grafana connection successful")
                    return True
                else:
                    logger.error(f"Grafana connection failed: {response.status_code}")
                    return False
        except Exception as e:
            logger.error(f"Error testing Grafana connection: {e}")
            return False


# 创建全局实例
grafana = GrafanaIntegration()